package main

import (
	"fmt"
	"sync"
	"time"
)

// # 简单的
// - 作业简单的题:实现一个线程安全的集合set，元素是string
// - 要求有
// - NewSet方法初始化
// - Add方法添加元素，添加重复元素可以去重
// - Del方法删除元素
// - Merge方法合并另一个set
// - PrintElement 方法打印所有元素
// - JudgeElement方法 检测输入的string 是否存在于set中
// - 总之就是set相关的方法
// - https://github.com/deckarep/golang-set

type SafeSet struct {
	sync.RWMutex
	m map[string]struct{}
}

// NewSet方法初始化
func NewSet() *SafeSet {
	return &SafeSet{
		m: make(map[string]struct{}),
	}
}

// - Add方法添加元素，添加重复元素可以去重
func (ss *SafeSet) Add(key string) {
	ss.Lock()
	defer ss.Unlock()
	ss.m[key] = struct{}{}
}

// - Del方法删除元素
func (ss *SafeSet) Del(key string) {
	ss.Lock()
	defer ss.Unlock()
	delete(ss.m, key)
}

// - PrintElement 方法打印所有元素
func (ss *SafeSet) PrintElement() (res []string) {
	ss.RLock()
	defer ss.RUnlock()
	for k := range ss.m {
		res = append(res, k)
	}
	return res
}

// - Merge方法合并另一个set
func (ss *SafeSet) Merge(set *SafeSet) {
	ss.Lock()
	defer ss.Unlock()
	keys := set.PrintElement()
	for _, k := range keys {
		ss.m[k] = struct{}{}
	}

}

// - JudgeElement方法 检测输入的string 是否存在于set中
func (ss *SafeSet) JudgeElement(key string) bool {
	ss.RLock()
	defer ss.RUnlock()
	_, ok := ss.m[key]
	return ok
}

func setAdd(set *SafeSet, n int) {
	for i := 0; i < n; i++ {
		key := fmt.Sprintf("key=%d", i)
		set.Add(key)
	}
}

func setDel(set *SafeSet, n int) {
	for i := 0; i < n; i++ {
		key := fmt.Sprintf("key=%d", i)
		set.Del(key)
	}
}

func main() {
	// 基础测试
	// s1 := NewSet()
	// setAdd(s1, 10)
	// fmt.Println(s1.PrintElement())
	// setDel(s1, 5)
	// fmt.Println(s1.PrintElement())

	// s2 := NewSet()
	// setAdd(s2, 20)
	// fmt.Println(s2.PrintElement())
	// s1.Merge(s2)
	// fmt.Println(s2.PrintElement())

	// 测试线程安全
	s1 := NewSet()
	go setAdd(s1, 100)
	go setDel(s1, 50)
	go fmt.Println(s1.PrintElement())

	// s2 := NewSet()
	// go setAdd(s2, 200)
	// go setDel(s2, 200)
	// go fmt.Println(s2.PrintElement())

	time.Sleep(10 * time.Second)
}
